//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include <iostream>
#include <fstream>

#include "ListSmile.h"
#include "ListAncestorMol.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceAncestor {

  bool DiffAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    if (*(ancestorA->ListIdAncestor()->Get(level)) != *(ancestorB->ListIdAncestor()->Get(level))) return false;
    else {
      if (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorA->ListIdAncestor()->Get(0))) {
        NodeT->Info(NULL); 
        NodeT->Info(ancestorB);
        ((TNode <AncestorMol>*)ref)->Info(NULL);
        ((TNode <AncestorMol>*)ref)->Info(ancestorA);
      }
      return true;
    }
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main (int argc, char **argv) {

  String* namefileAllSmiles   = new String();
  String* namefileAllAncestor = new String();
  String* namefileOutAncestor = new String();

  int     levelAncestor = 2;

  if (argc < 5) {
    cout << "Error. Please enter all arguments to execute correctly!" << endl;
    cout << "./CreateClusterGroups <Name Ancestor File> <Name Smile File> <Name Output Files> <#ancestor Level>" << endl;
    return 0;
  }
  else {
    namefileAllAncestor->In(argv[1]);
    namefileAllSmiles->In(argv[2]);
    namefileOutAncestor->In(argv[3]);
    levelAncestor = atoi(argv[4]); 
  }

  ListAncestorMol* listAncestorMol = new ListAncestorMol(namefileAllAncestor, namefileAllSmiles);

  listAncestorMol->LoadDataFiles();
  //listAncestorMol->OrderListByAncestorAscendentIterative();
  listAncestorMol->OrderListByAncestorCenteredIterativeX();
  listAncestorMol->WriteAncestorFile();
  int numberClusters = listAncestorMol->WriteClusterByAncestorFileInfo(levelAncestor, namefileOutAncestor->Out());

  TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;
  listAncestorMol->ListAncestor()->RepresentativeOcurrencesAfterOrdered(SpaceAncestor::DiffAncestor, representativeAncestorList, &levelAncestor);

  FILE *ClusterSummary, *SmilesCluster;
  int   position = 0;

  char command[1000];
  sprintf(command, "%s.Summary\0", namefileOutAncestor->Out());
  ClusterSummary = fopen(command, "w+");
  sprintf(command, "%s.SummarySmiles\0", namefileOutAncestor->Out());
  SmilesCluster = fopen(command, "w+");

  representativeAncestorList->SetInitial();
  fprintf(ClusterSummary, "Cluster Name\t Id Molecule\t  Cluster Size\n");
  fprintf(ClusterSummary, "----------------------------------------------------------\n");
  while (representativeAncestorList->SetNext()) {
    int count = listAncestorMol->ListAncestor()->NumberOcurrence(SpaceAncestor::EqualAncestor, representativeAncestorList->GetCurrentNode(), &levelAncestor);
    fprintf(ClusterSummary, "Cluster%05d\t%10s\t\t%d\n", ++position, representativeAncestorList->GetCurrent()->Smile()->Id(), count);
    fprintf(SmilesCluster, "%s %s\n", representativeAncestorList->GetCurrent()->Smile()->Code(), representativeAncestorList->GetCurrent()->Smile()->Id());
  }

  fclose(ClusterSummary);
  fclose(SmilesCluster);

  char* pathBegin = strtok(argv[3], ".");
  char* pathEnd   = strtok(NULL, ".");

  for (int i = 1; i <= numberClusters; i++) {

    char* nameSmiles = new char[strlen(pathBegin) + strlen(pathEnd) + strlen("ClusterXXXXX") + 20];
    sprintf(nameSmiles, "%sCluster%05d\0", pathBegin, i);
    sprintf(nameSmiles, "%s.%s\0", nameSmiles, pathEnd);

    char* nameOut = new char[strlen(pathBegin) + strlen(pathEnd) + strlen("ClusterXXXXX") + 20];
    sprintf(nameOut, "%sCluster%05d\0", pathBegin, i);
    sprintf(nameOut, "%s.%s\0", nameOut, pathEnd);

    String*    namefileSmiles   = new String(nameSmiles);
    String*    namefileOut      = new String(nameOut);
    ListSmile* listSmile        = new ListSmile();

    listSmile->ExtractSmiles(namefileSmiles);
    listSmile->ReadFile();

    sprintf(command, "rm %s\0", namefileSmiles->Out()); system(command);

    fstream smilesFile;

    smilesFile.open(namefileOut->Out(), ios::out);
    listSmile->AllSmiles()->SetInitial();
    while (listSmile->AllSmiles()->SetNext()) {
      char*  textOut = listSmile->AllSmiles()->GetCurrent()->OutToSmileStringWithInfo();
      smilesFile << textOut << endl;
      if (textOut) delete[] textOut;
    }
    smilesFile.close();

    delete namefileSmiles;
    delete namefileOut;

    delete listSmile;

    if (nameSmiles) delete[] nameSmiles;
    if (nameOut)    delete[] nameOut;

  }

  representativeAncestorList->TransferAll();

  if (namefileAllSmiles)          delete namefileAllSmiles;
  if (namefileAllAncestor)        delete namefileAllAncestor;
  if (namefileOutAncestor)        delete namefileOutAncestor;
  if (listAncestorMol)            delete listAncestorMol;
  if (representativeAncestorList) delete representativeAncestorList;

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//

